using System.Diagnostics;
using System.Diagnostics.Metrics;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

namespace WeatherSystem.API.Configurations
{
    /// <summary>
    /// OpenTelemetry配置扩展
    /// </summary>
    public static class OpenTelemetryConfiguration
    {
        public static readonly string ServiceName = "WeatherSystem.API";
        public static readonly string ServiceVersion = "1.0.0";
        
        // 自定义ActivitySource用于业务追踪
        public static readonly ActivitySource ActivitySource = new(ServiceName);
        
        // 自定义Meter用于业务指标
        public static readonly Meter Meter = new(ServiceName, ServiceVersion);
        
        // 业务指标计数器
        public static readonly Counter<long> WeatherDataCollectedCounter = 
            Meter.CreateCounter<long>("weather_data_collected_total", description: "采集的天气数据总数");
            
        public static readonly Counter<long> ApiRequestCounter = 
            Meter.CreateCounter<long>("api_requests_total", description: "API请求总数");
            
        public static readonly Histogram<double> ApiRequestDuration = 
            Meter.CreateHistogram<double>("api_request_duration_ms", description: "API请求持续时间", unit: "ms");
            
        public static readonly Counter<long> DataExportCounter = 
            Meter.CreateCounter<long>("data_exports_total", description: "数据导出总数");
            
        public static readonly Gauge<int> ActiveCitiesGauge = 
            Meter.CreateGauge<int>("active_cities_count", description: "活跃城市数量");
            
        public static readonly Counter<long> CacheHitCounter = 
            Meter.CreateCounter<long>("cache_hits_total", description: "缓存命中总数");
            
        public static readonly Counter<long> CacheMissCounter = 
            Meter.CreateCounter<long>("cache_misses_total", description: "缓存未命中总数");

        /// <summary>
        /// 配置OpenTelemetry服务
        /// </summary>
        public static IServiceCollection AddOpenTelemetryServices(this IServiceCollection services, IConfiguration configuration)
        {
            var resourceBuilder = ResourceBuilder.CreateDefault()
                .AddService(ServiceName, ServiceVersion)
                .AddAttributes(new Dictionary<string, object>
                {
                    ["environment"] = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development",
                    ["host.name"] = Environment.MachineName,
                    ["service.instance.id"] = Environment.MachineName + "-" + Environment.ProcessId
                });

            services.AddOpenTelemetry()
                .ConfigureResource(resource =>
                {
                    resource.AddService(ServiceName, ServiceVersion);
                    resource.AddAttributes(new Dictionary<string, object>
                    {
                        ["environment"] = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development",
                        ["host.name"] = Environment.MachineName,
                        ["service.instance.id"] = Environment.MachineName + "-" + Environment.ProcessId
                    });
                })
                .WithTracing(builder =>
                {
                    builder
                        .AddSource(ServiceName)
                        .AddSource("Microsoft.AspNetCore")
                        .AddSource("Microsoft.EntityFrameworkCore")
                        .AddAspNetCoreInstrumentation(options =>
                        {
                            options.RecordException = true;
                            options.Filter = httpContext =>
                            {
                                // 过滤健康检查和静态文件请求
                                var path = httpContext.Request.Path.ToString();
                                return !path.StartsWith("/health") && 
                                       !path.StartsWith("/swagger") &&
                                       !path.StartsWith("/_framework");
                            };
                            options.EnrichWithHttpRequest = (activity, httpRequest) =>
                            {
                                activity.SetTag("http.request.body.size", httpRequest.ContentLength);
                                activity.SetTag("user.id", httpRequest.HttpContext.User?.Identity?.Name);
                            };
                            options.EnrichWithHttpResponse = (activity, httpResponse) =>
                            {
                                activity.SetTag("http.response.body.size", httpResponse.ContentLength);
                            };
                        })
                        .AddHttpClientInstrumentation(options =>
                        {
                            options.RecordException = true;
                            options.FilterHttpRequestMessage = request =>
                            {
                                // 过滤内部健康检查请求
                                return !request.RequestUri?.PathAndQuery.Contains("/health") == true;
                            };
                        })
                        .AddEntityFrameworkCoreInstrumentation(options =>
                        {
                            options.SetDbStatementForText = true;
                            options.SetDbStatementForStoredProcedure = true;
                            options.EnrichWithIDbCommand = (activity, command) =>
                            {
                                activity.SetTag("db.operation", command.CommandType.ToString());
                                activity.SetTag("db.command_timeout", command.CommandTimeout);
                            };
                        })
                        .AddSqlClientInstrumentation(options =>
                        {
                            options.SetDbStatementForText = true;
                            options.RecordException = true;
                            options.EnableConnectionLevelAttributes = true;
                        });

                    // 配置导出器
                    var otlpEndpoint = configuration["OpenTelemetry:OtlpEndpoint"];
                    if (!string.IsNullOrEmpty(otlpEndpoint))
                    {
                        builder.AddOtlpExporter(options =>
                        {
                            options.Endpoint = new Uri(otlpEndpoint);
                            options.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
                        });
                    }

                    // 开发环境启用控制台导出
                    if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
                    {
                        builder.AddConsoleExporter();
                    }
                })
                .WithMetrics(builder =>
                {
                    builder
                        .AddMeter(ServiceName)
                        .AddMeter("Microsoft.AspNetCore.Hosting")
                        .AddMeter("Microsoft.AspNetCore.Server.Kestrel")
                        .AddHttpClientInstrumentation()
                        .AddAspNetCoreInstrumentation()
                        .AddPrometheusExporter();

                    // 配置OTLP指标导出
                    var otlpEndpoint = configuration["OpenTelemetry:OtlpEndpoint"];
                    if (!string.IsNullOrEmpty(otlpEndpoint))
                    {
                        builder.AddOtlpExporter((exporterOptions, metricReaderOptions) =>
                        {
                            exporterOptions.Endpoint = new Uri(otlpEndpoint);
                            exporterOptions.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
                            metricReaderOptions.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds = 10000;
                        });
                    }

                    // 开发环境启用控制台指标导出
                    if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
                    {
                        builder.AddConsoleExporter((exporterOptions, metricReaderOptions) =>
                        {
                            metricReaderOptions.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds = 30000;
                        });
                    }
                });

            return services;
        }

        /// <summary>
        /// 配置Prometheus指标端点
        /// </summary>
        public static IApplicationBuilder UseOpenTelemetryPrometheusMetrics(this IApplicationBuilder app)
        {
            app.UseOpenTelemetryPrometheusScrapingEndpoint();
            return app;
        }
    }

    /// <summary>
    /// 业务指标收集服务
    /// </summary>
    public interface IBusinessMetricsService
    {
        void RecordWeatherDataCollected(string cityId, string source);
        void RecordApiRequest(string endpoint, string method, double durationMs, int statusCode);
        void RecordDataExport(string exportType, int recordCount, string userId);
        void RecordCacheOperation(string operation, string cacheType, bool hit);
        void UpdateActiveCitiesCount(int count);
        Activity? StartActivity(string name, ActivityKind kind = ActivityKind.Internal);
    }

    /// <summary>
    /// 业务指标收集服务实现
    /// </summary>
    public class BusinessMetricsService : IBusinessMetricsService
    {
        public void RecordWeatherDataCollected(string cityId, string source)
        {
            OpenTelemetryConfiguration.WeatherDataCollectedCounter.Add(1, 
                new KeyValuePair<string, object?>("city.id", cityId),
                new KeyValuePair<string, object?>("data.source", source));
        }

        public void RecordApiRequest(string endpoint, string method, double durationMs, int statusCode)
        {
            OpenTelemetryConfiguration.ApiRequestCounter.Add(1,
                new KeyValuePair<string, object?>("http.method", method),
                new KeyValuePair<string, object?>("http.route", endpoint),
                new KeyValuePair<string, object?>("http.status_code", statusCode));

            OpenTelemetryConfiguration.ApiRequestDuration.Record(durationMs,
                new KeyValuePair<string, object?>("http.method", method),
                new KeyValuePair<string, object?>("http.route", endpoint),
                new KeyValuePair<string, object?>("http.status_code", statusCode));
        }

        public void RecordDataExport(string exportType, int recordCount, string userId)
        {
            OpenTelemetryConfiguration.DataExportCounter.Add(1,
                new KeyValuePair<string, object?>("export.type", exportType),
                new KeyValuePair<string, object?>("export.record_count", recordCount),
                new KeyValuePair<string, object?>("user.id", userId));
        }

        public void RecordCacheOperation(string operation, string cacheType, bool hit)
        {
            if (hit)
            {
                OpenTelemetryConfiguration.CacheHitCounter.Add(1,
                    new KeyValuePair<string, object?>("cache.operation", operation),
                    new KeyValuePair<string, object?>("cache.type", cacheType));
            }
            else
            {
                OpenTelemetryConfiguration.CacheMissCounter.Add(1,
                    new KeyValuePair<string, object?>("cache.operation", operation),
                    new KeyValuePair<string, object?>("cache.type", cacheType));
            }
        }

        public void UpdateActiveCitiesCount(int count)
        {
            OpenTelemetryConfiguration.ActiveCitiesGauge.Record(count);
        }

        public Activity? StartActivity(string name, ActivityKind kind = ActivityKind.Internal)
        {
            return OpenTelemetryConfiguration.ActivitySource.StartActivity(name, kind);
        }
    }
}